
from sgfmill import sgf as Sgf
from sgfmill import sgf_properties as Sgf_properties

from board import Board

class Metadata:
    def __init__(self, size, bname, wname, brank, wrank, komi, handicap):
        self.size = size
        self.bname = bname
        self.wname = wname
        self.brank = brank
        self.wrank = wrank
        self.komi = komi
        self.handicap = handicap

#Returns (metadata, list of setup stones, list of move stones)
#Setup and move stones are both pairs of (pla,loc)
def load_sgf_moves_exn(path):
    sgf_file = open(path,"rb")
    contents = sgf_file.read()
    sgf_file.close()

    game = Sgf.Sgf_game.from_bytes(contents)
    size = game.get_size()

    root = game.get_root()
    ab, aw, ae = root.get_setup_stones()
    setup = []
    if ab or aw:
        for (row,col) in ab:
            loc = Board.loc_static(col,size-1-row,size)
            setup.append((Board.BLACK,loc))
        for (row,col) in aw:
            loc = Board.loc_static(col,size-1-row,size)
            setup.append((Board.WHITE,loc))

        color,raw = root.get_raw_move()
        if color is not None:
            raise Exception("Found both setup stones and normal moves in root node")

    #Walk down the leftmost branch and assume that this is the game
    moves = []
    prev_pla = None
    seen_white_moves = False
    node = root
    while node:
        node = node[0]
        if node.has_setup_stones():
            raise Exception("Found setup stones after the root node")

        color,raw = node.get_raw_move()
        if color is None:
            raise Exception("Found node without move color")

        if color == 'b':
            pla = Board.BLACK
        elif color == 'w':
            pla = Board.WHITE
        else:
            raise Exception("Invalid move color: " + color)

        rc = Sgf_properties.interpret_go_point(raw, size)
        if rc is None: #pass
            loc = Board.PASS_LOC
        else:
            (row,col) = rc
            loc = Board.loc_static(col,size-1-row,size)

        #Forbid consecutive moves by the same player, unless the previous player was black and we've seen no white moves yet (handicap setup)
        if pla == prev_pla and not (prev_pla == Board.BLACK and not seen_white_moves):
            raise Exception("Multiple moves in a row by same player")
        moves.append((pla,loc))

        prev_pla = pla
        if pla == Board.WHITE:
            seen_white_moves = True

    #If there are multiple black moves in a row at the start, assume they are more handicap stones
    first_white_move_idx = 0
    while first_white_move_idx < len(moves) and moves[first_white_move_idx][0] == Board.BLACK:
        first_white_move_idx += 1
    if first_white_move_idx >= 2:
        setup.extend((pla,loc) for (pla,loc) in moves[:first_white_move_idx] if loc is not None)
        moves = moves[first_white_move_idx:]

    bname = root.get("PB")
    wname = root.get("PW")
    brank = (root.get("BR") if root.has_property("BR") else None)
    wrank = (root.get("WR") if root.has_property("WR") else None)
    komi = (root.get("KM") if root.has_property("KM") else None)
    rulesstr = (root.get("RU") if root.has_property("RU") else None)
    handicap = (root.get("HA") if root.has_property("HA") else None)

    rules = None
    if rulesstr is not None:
        if rulesstr.lower() == "japanese" or rulesstr.lower() == "jp":
            rules = {
                "koRule": "KO_SIMPLE",
                "scoringRule": "SCORING_TERRITORY",
                "multiStoneSuicideLegal": False,
                "encorePhase": 0,
                "passWouldEndPhase": False,
                "whiteKomi": komi
            }
        elif rulesstr.lower() == "chinese":
            rules = {
                "koRule": "KO_SIMPLE",
                "scoringRule": "SCORING_AREA",
                "multiStoneSuicideLegal": False,
                "encorePhase": 0,
                "passWouldEndPhase": False,
                "whiteKomi": komi
            }
        elif rulesstr.startswith("ko"):
            rules = {}
            origrulesstr = rulesstr
            rulesstr = rulesstr[2:]
            if rulesstr.startswith("SIMPLE"):
                rules["koRule"] = "KO_SIMPLE"
                rulesstr = rulesstr[6:]
            elif rulesstr.startswith("POSITIONAL"):
                rules["koRule"] = "KO_POSITIONAL"
                rulesstr = rulesstr[10:]
            elif rulesstr.startswith("SITUATIONAL"):
                rules["koRule"] = "KO_SITUATIONAL"
                rulesstr = rulesstr[11:]
            elif rulesstr.startswith("SPIGHT"):
                rules["koRule"] = "KO_SPIGHT"
                rulesstr = rulesstr[6:]
            else:
                raise Exception("Could not parse rules: " + origrulesstr)

            if rulesstr.startswith("score"):
                rulesstr = rulesstr[5:]
            else:
                raise Exception("Could not parse rules: " + origrulesstr)

            if rulesstr.startswith("AREA"):
                rules["scoringRule"] = "SCORING_AREA"
                rulesstr = rulesstr[4:]
            elif rulesstr.startswith("TERRITORY"):
                rules["scoringRule"] = "SCORING_TERRITORY"
                rulesstr = rulesstr[9:]
            else:
                raise Exception("Could not parse rules: " + origrulesstr)

            if rulesstr.startswith("sui"):
                rulesstr = rulesstr[3:]
            else:
                raise Exception("Could not parse rules: " + origrulesstr)

            if rulesstr.startswith("false"):
                rules["multiStoneSuicideLegal"] = False
                rulesstr = rulesstr[5:]
            elif rulesstr.startswith("true"):
                rules["multiStoneSuicideLegal"] = True
                rulesstr = rulesstr[4:]
            else:
                raise Exception("Could not parse rules: " + origrulesstr)

    metadata = Metadata(size, bname, wname, brank, wrank, komi, handicap)
    return metadata, setup, moves, rules
